/**
XenSim simulates xenbal.
Copyright (C) 2006 Travis Vachon

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
package xensim;

import java.util.Vector;
import java.io.FileWriter;
import java.io.IOException;



public class SimulatorExperiments extends junit.framework.TestCase {
	
	private static long second = 1000;
	private static long minute = 60*second;
	private static long PAGE_SIZE = 4 * SimGlobals.KB;
	private static long BANDWIDTH = 100 * SimGlobals.Mb;
	

	public void BenchmarkExperiment2() throws ConfigurationError{
		/*
		 * Sender initiated, fully workload, 5 minutes
		 */
		Vector<Node> nodes = new Vector<Node>();
		SimGlobals globals = new SimGlobals(nodes);
		long runtime = 5*minute;
		Simulator sim = new Simulator(runtime, globals);
	
		nodes.add(new Node(globals, "node1", 1000, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(1000,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		nodes.add(new Node(globals, "node2", 1000, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(1000,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
				

		Vector<Domain> domains = new Vector<Domain>();
		domains.add(new Domain(globals, "domain-1", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(1000,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));

		
		
		nodes.get(0).bootDomain(domains.get(0));


		assertTrue(nodes.get(0).numberOfDomains() == 2);
		assertTrue(nodes.get(1).numberOfDomains() == 1);

		
		//Set up monitors and balancers
		
		Monitor monitor = new Monitor(globals, "xensim/logs/livemigbench2.log");
		
		
		globals.eventQueue.add(new MigrationEvent(1*minute, nodes.get(0), domains.get(0), nodes.get(1)));
		
		sim.run();
		
		
		
		assertTrue(nodes.get(0).numberOfDomains() == 1);
		assertTrue(nodes.get(1).numberOfDomains() == 2);

		
	}
	
	public void Experiment1() throws ConfigurationError{
		/*
		 * Sender initiated, fully workload, 5 minutes
		 */
		Vector<Node> nodes = new Vector<Node>();
		SimGlobals globals = new SimGlobals(nodes);
		long runtime = 5*minute;
		Simulator sim = new Simulator(runtime, globals);
		nodes.add(new Node(globals, "node1", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		nodes.add(new Node(globals, "node2", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		
		nodes.add(new Node(globals, "node3", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		nodes.add(new Node(globals, "node4", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		
		Vector<Domain> domains = new Vector<Domain>();
		domains.add(new Domain(globals, "domain-1", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		domains.add(new Domain(globals, "domain-2", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		domains.add(new Domain(globals, "domain-3", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		domains.add(new Domain(globals, "domain-4", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		
		
		nodes.get(0).bootDomain(domains.get(0));
		nodes.get(1).bootDomain(domains.get(1));
		nodes.get(2).bootDomain(domains.get(2));
		nodes.get(2).bootDomain(domains.get(3));


		assertTrue(nodes.get(0).numberOfDomains() == 2);
		assertTrue(nodes.get(1).numberOfDomains() == 2);
		assertTrue(nodes.get(2).numberOfDomains() == 3);
		assertTrue(nodes.get(3).numberOfDomains() == 1);
		
		//Set up monitors and balancers
		
		Monitor monitor = new Monitor(globals, "xensim/logs/experiment1.log");
		
		for (Node node:nodes){
			globals.eventQueue.add(new BalanceEventSI(1*SimGlobals.TIME_CONSTANT,globals,monitor,node));
		}
		sim.run();
		
		
		
		assertTrue(nodes.get(0).numberOfDomains() == 2);
		assertTrue(nodes.get(1).numberOfDomains() == 2);
		assertTrue(nodes.get(2).numberOfDomains() == 2);
		assertTrue(nodes.get(3).numberOfDomains() == 2);
		
	}
	
	public void Experiment2() throws ConfigurationError{
		/*
		 * Sender initiated, fully workload, 5 minutes
		 */
		Vector<Node> nodes = new Vector<Node>();
		SimGlobals globals = new SimGlobals(nodes);
		long runtime = 5*minute;
		Simulator sim = new Simulator(runtime, globals);
		nodes.add(new Node(globals, "node1", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		nodes.add(new Node(globals, "node2", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		
		nodes.add(new Node(globals, "node3", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		nodes.add(new Node(globals, "node4", 650, 512 * SimGlobals.MB,
				PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
				new CPUGaussFn(650,0.05, 0.02), new ConstNetworkFn(10*SimGlobals.Kb)));
		
		Vector<Domain> domains = new Vector<Domain>();
		domains.add(new Domain(globals, "domain-1", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		domains.add(new Domain(globals, "domain-2", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		domains.add(new Domain(globals, "domain-3", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		domains.add(new Domain(globals, "domain-4", 96 * SimGlobals.MB,
				new ConstRateFn(0.005), new CPUGaussFn(650,0.95, 0.05),
				new ConstNetworkFn(10 * SimGlobals.Kb)));
		
		
		nodes.get(0).bootDomain(domains.get(0));
		nodes.get(1).bootDomain(domains.get(1));
		nodes.get(2).bootDomain(domains.get(2));
		nodes.get(2).bootDomain(domains.get(3));


		assertTrue(nodes.get(0).numberOfDomains() == 2);
		assertTrue(nodes.get(1).numberOfDomains() == 2);
		assertTrue(nodes.get(2).numberOfDomains() == 3);
		assertTrue(nodes.get(3).numberOfDomains() == 1);
		
		//Set up monitors and balancers
		
		Monitor monitor = new Monitor(globals, "xensim/logs/experiment2.log");
		
		for (Node node:nodes){
			globals.eventQueue.add(new BalanceEventSI(1*SimGlobals.TIME_CONSTANT,globals,monitor,node));
		}
		sim.run();
		
		
		
		assertTrue(nodes.get(0).numberOfDomains() == 2);
		assertTrue(nodes.get(1).numberOfDomains() == 2);
		assertTrue(nodes.get(2).numberOfDomains() == 2);
		assertTrue(nodes.get(3).numberOfDomains() == 2);
	}
	
	public void SimpleSILarge() throws ConfigurationError{
		/*
		 * Sender initiated, fully workload, 5 hours
		 */
		Vector<Node> nodes = new Vector<Node>();
		Vector<Domain> domains = new Vector<Domain>();
		SimGlobals globals = new SimGlobals(nodes);
		long runtime = 60*minute;
		Simulator sim = new Simulator(runtime, globals);
		
		for (int i = 0; i < 4; i++){
			Node node = new Node(globals, "node-"+i, 2000, 10 * SimGlobals.GB,
					PAGE_SIZE, BANDWIDTH, 100*SimGlobals.MB, new ConstRateFn(0.005), 
					new CPUGaussFn(2000,0.01, 0.02), new ConstNetworkFn(1*SimGlobals.Kb));
			nodes.add(node);
			
			
			if (i%2==0){
			for (int j = 0; j < 10; j++){
				Domain domain = new Domain(globals, "node-"+i+"-domain-"+j, 96 * SimGlobals.MB,
						new ConstRateFn(0.005), new CPUGaussFn(2000,0.25, 0.05),
						new ConstNetworkFn(10 * SimGlobals.Kb));
				node.bootDomain(domain);
				
			}
			}
		}
		

		assertTrue(nodes.get(0).numberOfDomains() == 11);
		assertTrue(nodes.get(1).numberOfDomains() == 1);
		assertTrue(nodes.get(2).numberOfDomains() == 11);
		assertTrue(nodes.get(3).numberOfDomains() == 1);
		
		//Set up monitors and balancers
		System.out.println("Starting!");
		Monitor monitor = new Monitor(globals, "xensim/logs/simplesilarge.log");
		
		for (Node node:nodes){
			globals.eventQueue.add(new BalanceEventSI(1*SimGlobals.TIME_CONSTANT,globals,monitor,node));
		}
		sim.run();
		
		
		
		
	}
	public static void main(String[] args) throws ConfigurationError{
		SimulatorExperiments tester = new SimulatorExperiments();
		
		tester.BenchmarkExperiment2();
		
	}
	
	
}
